﻿using System;
using System.Linq;
using System.Runtime.InteropServices;

namespace csharpcl
{
    public class Introp
    {
        public const string Dll_cl = "cl.dll";

        #region 测试代码

        [DllImport(Dll_cl)]
        public static extern void Add(int a, int b, ref int x);

        #endregion 测试代码

        #region 上下文、命令对象、程序、内核

        public static IntPtr CreateCommandQueue(ulong did, IntPtr ctx)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            CreateCommandQueue(did, ctx, ret);
            return ret;
        }

        public static IntPtr CreateContext(ulong did)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            CreateContext(did, ret);
            return ret;
        }

        public static IntPtr CreateKernal(IntPtr prg, string name)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            IntPtr pname = Marshal.StringToHGlobalAnsi(name);
            //Marshal.Copy(name.ToCharArray(), 0, pname, name.Length);
            CreateKernal(prg, pname, ret);
            return ret;
        }

        public static IntPtr CreateProgramCode(ulong did, IntPtr ctx, string clcode, out string error)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            char[] code = clcode.ToArray();
            var err = Marshal.AllocHGlobal(1024);
            int r = CreateProgramCode(did, ctx, code, ret, err);
            error = null;
            if (r != 0)
            {
                error = Marshal.PtrToStringAnsi(err);
            }
            Marshal.FreeHGlobal(err);
            return ret;
        }

        public static IntPtr CreateProgramFile(ulong did, IntPtr ctx, string file, out string error)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            char[] fs = file.ToArray();
            var err = Marshal.AllocHGlobal(1024);
            CreateProgramFile(did, ctx, fs, ret, err);
            error = Marshal.PtrToStringAnsi(err);
            Marshal.FreeHGlobal(err);
            return ret;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="kel"></param>
        /// <param name="global_work_size">每个纬度的工作组数量</param>
        /// <returns></returns>
        public static IntPtr Exec_CommandQueue(IntPtr queue, IntPtr kel, Int64[] global_work_size)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            int err = Exec_CommandQueue(queue, kel, global_work_size.Length, global_work_size, ret);
            if (err != 0)
            {
                throw new Exception("执行失败:" + err);
            }
            return ret;
        }

        /// <summary>
        /// 指定执行计算的纬度和工作组参数
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="kel"></param>
        /// <param name="work_dim">纬度数量：1,2,3</param>
        /// <param name="global_work_size">每个纬度的工作组数量</param>
        /// <returns></returns>
        public static IntPtr Exec_CommandQueue(IntPtr queue, IntPtr kel, int work_dim, Int64[] global_work_size)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            int err = Exec_CommandQueue(queue, kel, work_dim, global_work_size, ret);
            if (err != 0)
            {
                throw new Exception("执行失败:" + err);
            }
            return ret;
        }

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int CreateCommandQueue(ulong did, IntPtr ctx, IntPtr ptr);

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int CreateContext(ulong did, IntPtr ptr);

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int CreateKernal(IntPtr prg, IntPtr name, IntPtr ptr);

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int CreateProgramCode(ulong did, IntPtr ctx, char[] clcode, IntPtr ptr, IntPtr error);

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int CreateProgramFile(ulong did, IntPtr ctx, char[] file, IntPtr ptr, IntPtr error);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueue(IntPtr queue, IntPtr kel, int work_dim, Int64[] global_work_size, IntPtr pevent);

        #endregion 上下文、命令对象、程序、内核

        #region 读数据缓存

        public static void Exec_CommandQueueReadBuffer(IntPtr queue, IntPtr mem, int[] buff)
        {
            var ptr = Marshal.AllocHGlobal(sizeof(int) * buff.Length);
            int err = Exec_CommandQueueReadBuffer_int(queue, mem, ptr, buff.Length);
            Marshal.Copy(ptr, buff, 0, buff.Length);
            Marshal.FreeHGlobal(ptr);
            if (err != 0)
            {
                throw new Exception("读取数据失败:" + err);
            }
        }

        public static void Exec_CommandQueueReadBuffer(IntPtr queue, IntPtr mem, long[] buff)
        {
            var ptr = Marshal.AllocHGlobal(sizeof(long) * buff.Length);
            int err = Exec_CommandQueueReadBuffer_long(queue, mem, ptr, buff.Length);
            Marshal.Copy(ptr, buff, 0, buff.Length);
            Marshal.FreeHGlobal(ptr);
            if (err != 0)
            {
                throw new Exception("读取数据失败:" + err);
            }
        }

        public static void Exec_CommandQueueReadBuffer(IntPtr queue, IntPtr mem, float[] buff)
        {
            var ptr = Marshal.AllocHGlobal(sizeof(float) * buff.Length);
            int err = Exec_CommandQueueReadBuffer_float(queue, mem, ptr, buff.Length);
            Marshal.Copy(ptr, buff, 0, buff.Length);
            Marshal.FreeHGlobal(ptr);
            if (err != 0)
            {
                throw new Exception("读取数据失败:" + err);
            }
        }

        public static void Exec_CommandQueueReadBuffer(IntPtr queue, IntPtr mem, double[] buff)
        {
            var ptr = Marshal.AllocHGlobal(sizeof(double) * buff.Length);
            int err = Exec_CommandQueueReadBuffer_double(queue, mem, ptr, buff.Length);
            Marshal.Copy(ptr, buff, 0, buff.Length);
            Marshal.FreeHGlobal(ptr);
            if (err != 0)
            {
                throw new Exception("读取数据失败:" + err);
            }
        }

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_double(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_float(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_int(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_long(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_uint(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        [DllImport(Dll_cl)]
        private static extern int Exec_CommandQueueReadBuffer_ulong(IntPtr queue, IntPtr mem, IntPtr buff, int len);

        #endregion 读数据缓存

        #region 对象释放

        public static void ReleaseCommandQueue(IntPtr ptr)
        {
            ReleaseClObject(ptr, 2);
        }

        public static void ReleaseContext(IntPtr ptr)
        {
            ReleaseClObject(ptr, 3);
        }

        public static void ReleaseKernal(IntPtr ptr)
        {
            ReleaseClObject(ptr, 4);
        }

        public static void ReleaseMem(IntPtr ptr)
        {
            ReleaseClObject(ptr, 0);
        }

        public static void ReleaseProgram(IntPtr ptr)
        {
            ReleaseClObject(ptr, 1);
        }

        [DllImport(Dll_cl)]
        private static extern void ReleaseClObject(IntPtr device, int ty);

        #endregion 对象释放

        #region 设置内核变量

        public static void SetKernalLocalParam(IntPtr kel, int index, int size)
        {
            int err = SetKernalLocalParamk(kel, index, size);
            if (err != 0)
            {
                throw new Exception("设置内核参数(局部内存)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, int value)
        {
            var err = SetKernalParam_int(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(int)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, uint value)
        {
            var err = SetKernalParam_uint(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(uint)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, long value)
        {
            var err = SetKernalParam_long(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(long)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, ulong value)
        {
            var err = SetKernalParam_ulong(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(ulong)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, double value)
        {
            var err = SetKernalParam_double(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(double)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, float value)
        {
            var err = SetKernalParam_float(kel, index, value);
            if (err != 0)
            {
                throw new Exception("设置内核参数(float)错误:" + err);
            }
        }

        public static void SetKernalParam(IntPtr kel, int index, IntPtr buff)
        {
            int err = SetKernalParam_Bufferk(kel, index, buff);
            if (err != 0)
            {
                throw new Exception("设置内核参数(buffer)错误:" + err);
            }
        }

        [DllImport(dllName: Dll_cl, EntryPoint = "SetKernalLocalParam")]
        private static extern int SetKernalLocalParamk(IntPtr kel, int index, int size);

        [DllImport(dllName: Dll_cl, EntryPoint = "SetKernalParam_Buffer")]
        private static extern int SetKernalParam_Bufferk(IntPtr kel, int index, IntPtr buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_double(IntPtr kel, int index, double buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_float(IntPtr kel, int index, float buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_int(IntPtr kel, int index, int buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_long(IntPtr kel, int index, long buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_uint(IntPtr kel, int index, uint buff);

        [DllImport(Dll_cl)]
        private static extern int SetKernalParam_ulong(IntPtr kel, int index, ulong buff);

        #endregion 设置内核变量

        #region 数组缓存

        private enum BufferType : int
        {
            Input = 0x01,
            Output = 0x02,
            InputOutput = 0x03,
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, int[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_int(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, uint[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_uint(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, long[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_long(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, ulong[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_ulong(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, double[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_double(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputBuffer(IntPtr ctx, float[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_float(ctx, pbu, buff.Length, ret, (int)BufferType.Input);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, int[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_int(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, uint[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_uint(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, long[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_long(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, ulong[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_ulong(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, double[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_double(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClInputOutputBuffer(IntPtr ctx, float[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_float(ctx, pbu, buff.Length, ret, (int)BufferType.InputOutput);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, int[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_int(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, uint[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_uint(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, long[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_long(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, ulong[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_ulong(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, double[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_double(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        public static IntPtr CreateClOutputBuffer(IntPtr ctx, float[] buff)
        {
            IntPtr ret = Marshal.AllocHGlobal(IntPtr.Size);
            var pbu = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            CreateClBuffer_float(ctx, pbu, buff.Length, ret, (int)BufferType.Output);
            return ret;
        }

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_double(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_float(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_int(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_long(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_uint(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        [DllImport(Dll_cl)]
        private static extern void CreateClBuffer_ulong(IntPtr ctx, IntPtr buff, int size, IntPtr pbuff, int ty);

        #endregion 数组缓存

        #region 平台

        public static ulong[] GetPlatformIds()
        {
            int count = 0;
            int r = GetPlatforms(null, ref count);
            if (r != 0)
            {
                return null;
            }
            ulong[] pid = new ulong[count];
            r = GetPlatforms(pid, ref count);
            return pid;
        }

        public static string GetPlatformName(ulong platformId)
        {
            string ret = null;
            int len = 0;
            if (Introp.GetPlatformName(platformId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(len);
                if (Introp.GetPlatformName(platformId, ptr, ref len) == 0)
                {
                    ret = Marshal.PtrToStringAnsi(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int GetPlatformName(ulong pid, IntPtr ptr, ref int length);

        [DllImport(Dll_cl, CallingConvention = CallingConvention.StdCall)]
        private static extern int GetPlatforms(ulong[] pid, ref int count);

        #endregion 平台

        #region 设备

        public static string GetDeviceExtensions(ulong dId)
        {
            string ret = null;
            int len = 0;
            if (Introp.GetDeviceExtensions(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(len);
                if (Introp.GetDeviceExtensions(dId, ptr, ref len) == 0)
                {
                    ret = Marshal.PtrToStringAnsi(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static ulong[] GetDeviceIds(ulong platformId)
        {
            int num = 0;
            if (GetDevices(platformId, null, ref num) != 0)
                return null;
            if (num == 0)
                return new ulong[0];
            ulong[] ret = new ulong[num];
            if (GetDevices(platformId, ret, ref num) != 0)
                return null;
            return ret;
        }

        public static long GetDeviceMaxComputeUnits(ulong dId)
        {
            long ret = -1;
            int len = 4;
            if (Introp.GetDeviceMaxComputeUnits(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(sizeof(byte) * len);
                if (Introp.GetDeviceMaxComputeUnits(dId, ptr, ref len) == 0)
                {
                    ret = Marshal.ReadInt32(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static uint GetDeviceMaxWorkItemDimensions(ulong dId)
        {
            uint ret = 0;
            int len = 4;
            if (Introp.GetDeviceMaxWorkItemDimensions(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(sizeof(byte) * len);
                if (Introp.GetDeviceMaxWorkItemDimensions(dId, ptr, ref len) == 0)
                {
                    ret = (uint)Marshal.ReadInt32(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static int GetDeviceMaxWorkGroupSize(ulong dId)
        {
            int ret = -1;
            int len = 4;
            if (Introp.GetDeviceMaxWorkGroupSize(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(sizeof(byte) * len);
                if (Introp.GetDeviceMaxWorkGroupSize(dId, ptr, ref len) == 0)
                {
                    ret = Marshal.ReadInt32(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static long[] GetDeviceMaxWorkItemSizes(ulong dId)
        {
            long[] ret = null;
            int len = 4;
            if (Introp.GetDeviceMaxWorkItemSizes(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(sizeof(byte) * len);
                if (Introp.GetDeviceMaxWorkItemSizes(dId, ptr, ref len) == 0)
                {
                    var l = len / sizeof(long);
                    ret = new long[l];
                    for (int i = 0; i < l; i++)
                    {
                        ret[i] = Marshal.ReadInt64(ptr, sizeof(long) * i);
                    }
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static string GetDeviceName(ulong dId)
        {
            string ret = null;
            int len = 0;
            if (Introp.GetDeviceName(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(len);
                if (Introp.GetDeviceName(dId, ptr, ref len) == 0)
                {
                    ret = Marshal.PtrToStringAnsi(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        public static long GetDevicePECount(ulong did)
        {
            long len = 0;
            int ret = Introp.GetDevicePECount(did, ref len);
            if (ret == 0)
            {
                return len;
            }
            return -Math.Abs(ret);
        }

        public static string GetDeviceVersion(ulong dId)
        {
            string ret = null;
            int len = 0;
            if (Introp.GetDeviceVersion(dId, IntPtr.Zero, ref len) == 0)
            {
                var ptr = Marshal.AllocHGlobal(len);
                if (Introp.GetDeviceVersion(dId, ptr, ref len) == 0)
                {
                    ret = Marshal.PtrToStringAnsi(ptr);
                }
                Marshal.FreeHGlobal(ptr);
            }
            return ret;
        }

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int GetDeviceExtensions(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl)]
        private static extern int GetDeviceMaxComputeUnits(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl)]
        private static extern int GetDeviceMaxWorkItemDimensions(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl)]
        private static extern int GetDeviceMaxWorkGroupSize(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl)]
        private static extern int GetDeviceMaxWorkItemSizes(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl)]
        private static extern int GetDeviceName(ulong did, IntPtr ptr, ref int length);

        [DllImport(Dll_cl, CallingConvention = CallingConvention.StdCall)]
        private static extern int GetDevicePECount(ulong pid, ref long pecount);

        [DllImport(Dll_cl, CallingConvention = CallingConvention.StdCall)]
        private static extern int GetDevices(ulong pid, ulong[] did, ref int count);

        [DllImport(Dll_cl, CharSet = CharSet.Ansi)]
        private static extern int GetDeviceVersion(ulong did, IntPtr ptr, ref int length);

        #endregion 设备
    }
}